#include "eGUI_App.hpp"
#include "log.h"
#include "task_main.h"
#include "arm.hpp"
#include "interface_uart.hpp"
#include "track_config.hpp"
extern arm Arm;

eGUI_InputBox *inputBoxCommon = new eGUI_InputBox(0, NULL, eGUI_InputBox::NULL_DATA, NULL);
eGUI_Page *tempInputPage = new eGUI_Page(inputBoxCommon);
#define NewTextList(name)  __weak void ccb##name(uint32_t key);\
                eGUI_Page* pageTL_##name = new eGUI_Page(eGUI_PAGE_TYPE_TEXTLIST, ccb##name)
#define DrawStrCallback(name, _fmt, ...)\
                void dscb_##name(char* buf, size_t size){snprintf(buf, size, _fmt, ##__VA_ARGS__);}

#define NewInputBox2(Name, bindData1, bindData2, type, format)                            \
    void clickcb_##Name##_inputBox(uint32_t key)                                          \
    {                                                                                     \
        switch (key) {                                                                    \
            case 'D':                                                                     \
                tempInputPage->u.inputBox->setInputBox(0, (bindData1), (type), (format)); \
                egui.jumpPush(tempInputPage, true);                                       \
                break;                                                                    \
            case 'E':                                                                     \
                tempInputPage->u.inputBox->setInputBox(0, (bindData2), (type), (format)); \
                egui.jumpPush(tempInputPage, true);                                       \
                break;                                                                    \
            default:                                                                      \
                break;                                                                    \
        }                                                                                 \
    }
#define NewInputBox1(Name, bindData1, type, format)                                       \
    void clickcb_##Name##_inputBox(uint32_t key)                                          \
    {                                                                                     \
        switch (key) {                                                                    \
            case 'E':                                                                     \
                tempInputPage->u.inputBox->setInputBox(0, (bindData1), (type), (format)); \
                egui.jumpPush(tempInputPage, true);                                       \
                break;                                                                    \
            default:                                                                      \
                break;                                                                    \
        }                                                                                 \
    }

#define NewClickCB(Name, KEY, doSomething) \
    void clickcb_##Name(uint32_t key) { if (key == (KEY)) { doSomething } }
#define NewClickCB2(Name, KEY1, KEY2, doSomething1, doSomething2) \
    void clickcb_##Name(uint32_t key) { if (key == (KEY1)) { doSomething1 }else if(key == (KEY2)) {doSomething2}}

void ccbBase(uint32_t key)
{
    eGUI_TextList& TL = *egui.page->u.textList;
    switch (key)
    {
    case 'u':
        TL.moveCursor(-1);
        break;
    case 'd':
        TL.moveCursor(1);
        break;
    case 0x04:
        egui.jumpPop(true);
        break;
    }
}

/*------------ Text list Create ------------*/
NewTextList(Main);
NewTextList(Debug);
NewTextList(ArmCtrl);
NewTextList(ArmConfig);
NewTextList(Settings);

/*------------ Draw Item String Callback ------------*/
// ArmController
int MoveStepX1 = 50,MoveStepY1 = 50;
int MoveStepX2 = -50,MoveStepY2 = -50;
int setStepX, setStepY;
float setAngleX = 10.0, setAngleY = 10.0;
NewClickCB(armConfigEntry, 'E', egui.jumpPush(pageTL_ArmConfig, true);)
NewClickCB(resetArm, 'E', Arm.startReset();)
NewClickCB(armTrack, 'E', Arm.trackObject(trackReceive.readResult(trackReceive.findResult(&trackconfig)));)
DrawStrCallback(motorXAngle, "  XAngle:%.2f   ", Arm.stepperX.getAngle())
DrawStrCallback(motorYAngle, "  YAngle:%.2f   ", Arm.stepperY.getAngle())
DrawStrCallback(motorXSteps, "  XSteps:%ld    ", (long)Arm.stepperX.getStep())
DrawStrCallback(motorYSteps, "  YSteps:%ld    ", (long)Arm.stepperY.getStep())
DrawStrCallback(motorXSpeed, "  XSpeed:%.4lf r/s   ", Arm.stepperX.getSpeed())
DrawStrCallback(motorYSpeed, "  YSpeed:%.4lf r/s   ", Arm.stepperY.getSpeed())
DrawStrCallback(motorLimitSW, "  x:%d,y:%d   ", Arm.stepperX.limitsw1.getState(), Arm.stepperY.limitsw1.getState())

DrawStrCallback(armGoAimStep, "  Step X:%d Y:%d   ", setStepX, setStepY)
NewInputBox2(configStep, &setStepX, &setStepY, eGUI_InputBox::INT32_DATA, "%d")
DrawStrCallback(armGoAimAngle, "  Angle X:%.2f Y:%.2f", setAngleX, setAngleY)
NewInputBox2(configAngle, &setAngleX, &setAngleY, eGUI_InputBox::F32_DATA, "%.2f")      
NewClickCB2(startGoAim, 'E', '0', Arm.startGoAim(setStepX, setStepY);, \
            Arm.startGoAim(Arm.stepperX.angleToStep(setAngleX), Arm.stepperY.angleToStep(setAngleY));)
DrawStrCallback(armMoveConfig1, "  MStep X+:%d Y+:%d   ", MoveStepX1, MoveStepY1)
NewInputBox2(armMoveConfig1, &MoveStepX1, &MoveStepY1, eGUI_InputBox::INT32_DATA, "%d")
DrawStrCallback(armMoveConfig2, "  MStep X-:%d Y-:%d   ", MoveStepX2, MoveStepY2)
NewInputBox2(armMoveConfig2, &MoveStepX2, &MoveStepY2, eGUI_InputBox::INT32_DATA, "%d")
void clickcb_startMove(uint32_t key)
{
    static int CaliCnt = 0;
    switch (key)
    {
    case '8':
        Arm.stepperY.moveStep(MoveStepY1);
        break;
    case '2':
        Arm.stepperY.moveStep(MoveStepY2);
        break;
    case '4':
        Arm.stepperX.moveStep(MoveStepX2);
        break;
    case '6':
        Arm.stepperX.moveStep(MoveStepX1);
        break;
    case '5':
        Queue_Printf(&htx1, "[%d]Arm info:%lld,%lld,%.02lf,%.02lf\r\n", CaliCnt++, Arm.stepperX.getStep(), Arm.stepperY.getStep(),Arm.stepperX.getAngle(),Arm.stepperY.getAngle());
        Beep(100);
        break;
    case 'D':
        CaliCnt = 0;
        Queue_Printf(&htx1, "clear calicnt\n\r");
        break;
    case 'E':
        Queue_Printf(&htx1, "back %d to %d\n\r",CaliCnt, CaliCnt-1);
        CaliCnt--;
        break;
    }
}
// ArmConfigure
DrawStrCallback(resetSpeedSet, "  Rst Speed:%.2lf , %.2lf   ", Arm.resetConfig.speedX, Arm.resetConfig.speedY)
NewInputBox2(resetSpeedSet, &Arm.resetConfig.speedX, &Arm.resetConfig.speedY, eGUI_InputBox::F32_DATA, "%.2f")
DrawStrCallback(goAimSpeedSet, "  GoAim Speed:%.2lf , %.2lf   ", Arm.goaimConfig.speedX, Arm.goaimConfig.speedY)
NewInputBox2(goAimSpeedSet, &Arm.goaimConfig.speedX, &Arm.goaimConfig.speedY, eGUI_InputBox::F32_DATA, "%.2f")
DrawStrCallback(xLimitSet, "  XLimit enable:%s  ", Arm.stepperX.limitStepState ? "yes" : "no")
NewInputBox1(xLimitSet, &Arm.stepperX.limitStepState, eGUI_InputBox::BOOL_DATA, "%d")
DrawStrCallback(yLimitSet, "  YLimit enable:%s  ", Arm.stepperY.limitStepState ? "yes" : "no")
NewInputBox1(yLimitSet, &Arm.stepperY.limitStepState, eGUI_InputBox::BOOL_DATA, "%d")
DrawStrCallback(xResetDirSet, "  XReset dir:%d   ", Arm.resetConfig.dirX) 
NewInputBox1(xResetDirSet, &Arm.resetConfig.dirX, eGUI_InputBox::INT8_DATA, "%d")
DrawStrCallback(yResetDirSet, "  YReset dir:%d   ", Arm.resetConfig.dirY)
NewInputBox1(yResetDirSet, &Arm.resetConfig.dirY, eGUI_InputBox::INT8_DATA, "%d")
DrawStrCallback(resetNumSet, "  Num of arm reset:%d  ", Arm.resetConfig.resetCnt)
NewInputBox1(resetNumSet, &Arm.resetConfig.resetCnt, eGUI_InputBox::UINT8_DATA, "%d")
DrawStrCallback(resetAgainOffsetXSet, "  XARst offset:%d  ", Arm.resetConfig.againResetOffsetStepX)
NewInputBox1(resetAgainOffsetXSet, &Arm.resetConfig.againResetOffsetStepX, eGUI_InputBox::INT32_DATA, "%d")
DrawStrCallback(resetAgainOffsetYSet, "  YARst offset:%d  ", Arm.resetConfig.againResetOffsetStepY)
NewInputBox1(resetAgainOffsetYSet, &Arm.resetConfig.againResetOffsetStepY, eGUI_InputBox::INT32_DATA, "%d")
// system settings
DrawStrCallback(systemTime, " System time:%d ", HAL_GetTick()/1000)



void BSP_GUI_Init(void)
{
    egui.page = pageTL_Main;
    egui.ctrlcb = ccbMain;
    eGUI_TextList *TL = pageTL_Main->u.textList;
    *TL << "<Main page>"
        << " debug page (E)"
        << " Arm control (E)"
        << " system settings (E)";

    TL = pageTL_Debug->u.textList;
    *TL << "<Debug page>"
        << " First Page";

    TL = pageTL_ArmCtrl->u.textList;
    *TL << "<Arm control page>"
        << " Arm configure (E)" << clickcb_armConfigEntry
        << " Arm reset start (E)" << clickcb_resetArm
        << " Arm tracking start (E)" << clickcb_armTrack
        << " <Arm go aim>"
        << "  Go step(E) / Go angle(0)"  << clickcb_startGoAim
        << dscb_armGoAimStep << clickcb_configStep_inputBox
        << dscb_armGoAimAngle
        << " <Arm move>"
        << dscb_armMoveConfig1 << clickcb_armMoveConfig1_inputBox
        << dscb_armMoveConfig2 << clickcb_armMoveConfig2_inputBox
        << "  Move (8/2/4/6/5)" << clickcb_startMove
        << " <MotorX info>"
        << dscb_motorXAngle
        << dscb_motorXSteps
        << dscb_motorXSpeed
        << " <MotorY info>"
        << dscb_motorYAngle
        << dscb_motorYSteps
        << dscb_motorYSpeed
        << " <Limit info>"
        << dscb_motorLimitSW;

    TL = pageTL_ArmConfig->u.textList;
    *TL << "<Arm config page>"
        << " <Speed settings>"
        << dscb_resetSpeedSet << clickcb_resetSpeedSet_inputBox
        << dscb_goAimSpeedSet << clickcb_goAimSpeedSet_inputBox
        << " <Limit settings>"
        << dscb_xLimitSet << clickcb_xLimitSet_inputBox
        << dscb_yLimitSet << clickcb_yLimitSet_inputBox
        << " <Reset settings>"
        << dscb_xResetDirSet << clickcb_xResetDirSet_inputBox
        << dscb_yResetDirSet << clickcb_yResetDirSet_inputBox
        << dscb_resetNumSet << clickcb_resetNumSet_inputBox
        << dscb_resetAgainOffsetXSet << clickcb_resetAgainOffsetXSet_inputBox
        << dscb_resetAgainOffsetYSet << clickcb_resetAgainOffsetYSet_inputBox;

    TL = pageTL_Settings->u.textList;
    *TL << "<Seting Page>"
        << dscb_systemTime
        << " System info";

}

/*------------ Text list Ctrl Callback ------------*/
void ccbMain(uint32_t key)
{
    eGUI_TextList& TL = *egui.page->u.textList;
    switch (key)
    {
    case 'E':
        switch (TL.getItemSelect())
        {
        case 1:
            egui.jumpPush(pageTL_Debug, true);
            break;
        case 2:
            egui.jumpPush(pageTL_ArmCtrl, true);
            break;
        case 3:
            egui.jumpPush(pageTL_Settings, true);
            break;
        }
        break;
    default:
        ccbBase(key);
        break;
    }
    
}
void ccbDebug(uint32_t key)
{
    eGUI_TextList& TL = *egui.page->u.textList;
    eString str1("text list item:");
    switch (key)
    {
    case 'E':
        if (str1.mSize() == NULL) break;
        str1 += str1.format("%d", TL.itemList->len);
        TL << str1;
        TL.moveCursor(1);
        break;
    case 'D':
        TL.deleteItemString(TL.getItemSelect());
        break;
    case 0x02:
        TL << "AbcdeAbcdeAbcdeAbcdeAbcdeAbcdeAbcdeAbcde";
        break;
    default:
        ccbBase(key);
        break;
    }
}
void ccbArmConfig(uint32_t key)
{
    eGUI_TextList& TL = *egui.page->u.textList;
    if (TL.getItemString()->click) TL.getItemString()->click(key);
    switch (key)
    {
    case 'E':
        switch (TL.getItemSelect())
        {
        case 7:
            // Arm.stepperY.reset(-1);
            break;
        default:
            break;
        }
        break;
    case 'D':
        // TL.deleteItemString(TL.getItemSelect());
        break;
    default:
        ccbBase(key);
        break;
    }
}
void ccbArmCtrl(uint32_t key)
{
    eGUI_TextList& TL = *egui.page->u.textList;
    if (TL.getItemString()->click) TL.getItemString()->click(key);
    switch (key)
    {
    case 'E':
        switch (TL.getItemSelect())
        {
        case 7:
            // Arm.stepperY.reset(-1);
            break;
        default:
            break;
        }
        break;
    case 'D':

        break;
    default:
        ccbBase(key);
        break;
    }
}
void ccbSettings(uint32_t key)
{
    // eGUI_TextList& TL = *egui.page->u.textList;
    switch (key)
    {
    case 'E':
        
        break;
    case 'D':

        break;
    default:
        ccbBase(key);
        break;
    }
}
